<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>汉字宽高测量</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }
        canvas {
            border: 1px solid #ccc;
            margin: 10px 0;
        }
        .result {
            margin: 10px 0;
            padding: 10px;
            background-color: #f0f0f0;
            border-radius: 4px;
        }
        .distinct-size {
            margin: 10px 0;
            padding: 10px;
            background-color: #e0f0ff;
            border-radius: 4px;
        }
        .unicode-range {
            margin: 10px 0;
            padding: 10px;
            background-color: #ffe0e0;
            border-radius: 4px;
        }
        .font-section {
            margin: 20px 0;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <h1>汉字宽高测量</h1>
    
    <div class="font-section">
        <h2>黑体 (SimHei) 字体</h2>
        <canvas id="textCanvasSimHei" width="800" height="400"></canvas>
        <div id="resultsSimHei" class="result"></div>
        <div id="distinctSizesSimHei" class="distinct-size"></div>
    </div>
    
    <div class="font-section">
        <h2>cursive 字体</h2>
        <canvas id="textCanvasCursive" width="800" height="400"></canvas>
        <div id="resultsCursive" class="result"></div>
        <div id="distinctSizesCursive" class="distinct-size"></div>
    </div>
    
    <div id="unicodeInfo" class="unicode-range"></div>
    
    <script>
        /**
         * 测量汉字的宽度和高度
         * @param {CanvasRenderingContext2D} ctx - Canvas 上下文
         * @param {string} text - 要测量的文本
         * @param {number} fontSize - 字体大小
         * @param {string} fontFamily - 字体族
         * @returns {Object} 包含宽度和高度的对象
         */
        function measureText(ctx, text, fontSize, fontFamily) {
            // 设置字体
            ctx.font = `${fontSize}px ${fontFamily}`;
            
            // 测量文本宽度
            const metrics = ctx.measureText(text);
            const width = metrics.width;
            
            // 估算文本高度（基于字体大小）
            // 通常高度约为字体大小的 1.2 倍
            // const height = fontSize * 1.2;
            let height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent; 
            // let height = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; 


            return {
                text: text,
                width: parseFloat(width.toFixed(6)),
                height: parseFloat(height.toFixed(6))
            };
        }
        
        /**
         * 在画布上绘制文本
         * @param {CanvasRenderingContext2D} ctx - Canvas 上下文
         * @param {string} text - 要绘制的文本
         * @param {number} x - x 坐标
         * @param {number} y - y 坐标
         * @param {number} fontSize - 字体大小
         * @param {string} fontFamily - 字体族
         */
        function drawText(ctx, text, x, y, fontSize, fontFamily) {
            ctx.font = `${fontSize}px ${fontFamily}`;
            ctx.fillText(text, x, y);
            
            // 绘制基线参考线
            ctx.strokeStyle = '#ff0000';
            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(x + ctx.measureText(text).width, y);
            ctx.stroke();
        }
        
        /**
         * 统计不同的宽高组合
         * @param {Array} results - 测量结果数组
         * @returns {Array} 不同的宽高组合数组
         */
        function getDistinctSizes(results) {
            const distinctSizes = [];
            const sizeMap = new Map();
            
            results.forEach(result => {
                const key = `${result.width}x${result.height}`;
                if (!sizeMap.has(key)) {
                    sizeMap.set(key, {
                        width: result.width,
                        height: result.height,
                        chars: [result.text],
                        count: 1
                    });
                } else {
                    sizeMap.get(key).chars.push(result.text);
                    sizeMap.get(key).count++;
                }
            });
            
            return Array.from(sizeMap.values());
        }
        
        /**
         * 通过 Unicode 范围生成汉字
         * @param {number} start - Unicode 起始码点
         * @param {number} end - Unicode 结束码点
         * @param {number} count - 要生成的汉字数量
         * @returns {Array} 汉字数组
         */
        function generateChineseCharsFromUnicode(start, end, count) {
            const chars = [];
            const range = end - start + 1;
            
            // 为了确保不重复，如果请求的数量大于范围，则使用整个范围
            const actualCount = Math.min(count, range);
            
            // 生成唯一随机索引
            const indices = new Set();
            while (indices.size < actualCount) {
                const index = Math.floor(Math.random() * range);
                indices.add(index);
            }
            
            // 根据索引生成字符
            indices.forEach(index => {
                const codePoint = start + index;
                chars.push(String.fromCodePoint(codePoint));
            });
            
            return chars;
        }
        
        /**
         * 获取 Unicode 范围信息
         * @returns {Array} Unicode 范围信息数组
         */
        function getUnicodeRanges() {
            return [
                { name: 'CJK 统一汉字', start: 0x4E00, end: 0x9FFF, description: '最常用的汉字范围' },
                { name: 'CJK 扩展 A', start: 0x3400, end: 0x4DBF, description: '扩展汉字 A' },
                { name: 'CJK 扩展 B', start: 0x20000, end: 0x2A6DF, description: '扩展汉字 B' },
                { name: 'CJK 扩展 C', start: 0x2A700, end: 0x2B73F, description: '扩展汉字 C' },
                { name: 'CJK 扩展 D', start: 0x2B740, end: 0x2B81F, description: '扩展汉字 D' },
                { name: 'CJK 扩展 E', start: 0x2B820, end: 0x2CEAF, description: '扩展汉字 E' },
                { name: 'CJK 扩展 F', start: 0x2CEB0, end: 0x2EBEF, description: '扩展汉字 F' },
                { name: 'CJK 兼容汉字', start: 0xF900, end: 0xFAFF, description: '兼容汉字' }
            ];
        }
        
        /**
         * 处理特定字体的测量和显示
         * @param {string} fontFamily - 字体族名称
         * @param {string} canvasId - Canvas 元素 ID
         * @param {string} resultsId - 结果显示元素 ID
         * @param {string} distinctSizesId - 不同尺寸显示元素 ID
         */
        function processFontMeasurements(fontFamily, canvasId, resultsId, distinctSizesId) {
            // 获取元素
            const canvas = document.getElementById(canvasId);
            const ctx = canvas.getContext('2d');
            const resultsDiv = document.getElementById(resultsId);
            const distinctSizesDiv = document.getElementById(distinctSizesId);
            
            // 设置字体大小
            const fontSize = 48;
            
            // 获取 Unicode 范围信息
            const unicodeRanges = getUnicodeRanges();
            
            // 从主要的 CJK 统一汉字范围生成汉字
            const mainRange = unicodeRanges[0]; // CJK 统一汉字
            const chineseChars = generateChineseCharsFromUnicode(mainRange.start, mainRange.end, 20000);
            
            // 存储结果
            const results = [];
            
            // 测量每个汉字
            chineseChars.forEach(char => {
                const result = measureText(ctx, char, fontSize, fontFamily);
                results.push(result);
            });
            
            // 在画布上绘制汉字
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            let x = 20;
            const y = 100;
            const spacing = 80;
            
            chineseChars.forEach((char, index) => {
                drawText(ctx, char, x, y, fontSize, fontFamily);
                x += spacing;
            });
            
            // 显示结果
            let resultsHTML = '<h3>测量结果:</h3>';
            resultsHTML += '<ul>';
            
            // results.forEach(result => {
            //     resultsHTML += `
            //         <li>
            //             字符: "${result.text}" (U+${result.text.codePointAt(0).toString(16).toUpperCase()}) - 
            //             宽度: ${result.width}px, 
            //             高度: ${result.height}px
            //         </li>
            //     `;
            // });
            
            resultsHTML += '</ul>';
            
            resultsDiv.innerHTML = resultsHTML;
            
            // 统计不同的宽高组合
            const distinctSizes = getDistinctSizes(results);
            
            let distinctSizesHTML = '<h3>不同的宽高组合:</h3>';
            distinctSizesHTML += `<p>共有 ${distinctSizes.length} 种不同的宽高组合:</p>`;
            distinctSizesHTML += '<ul>';
            
            distinctSizes.forEach((size, index) => {
                distinctSizesHTML += `
                    <li>
                        宽度: ${size.width}px, 高度: ${size.height}px
                        <br>字符: ${size.chars.join(', ')}
                        <br>数量: ${size.count}
                    </li>
                `;
            });
            
            distinctSizesHTML += '</ul>';
            
            distinctSizesDiv.innerHTML = distinctSizesHTML;
        }
        
        // 显示 Unicode 范围信息
        const unicodeRanges = getUnicodeRanges();
        let unicodeInfoHTML = '<h2>Unicode 范围信息:</h2>';
        unicodeInfoHTML += '<ul>';
        
        unicodeRanges.forEach(range => {
            unicodeInfoHTML += `
                <li>
                    ${range.name}: U+${range.start.toString(16).toUpperCase()}-U+${range.end.toString(16).toUpperCase()}
                    <br>描述: ${range.description}
                    <br>字符数: ${range.end - range.start + 1}
                </li>
            `;
        });
        
        unicodeInfoHTML += '</ul>';
        document.getElementById('unicodeInfo').innerHTML = unicodeInfoHTML;
        
        // 处理黑体字体测量
        processFontMeasurements('SimHei', 'textCanvasSimHei', 'resultsSimHei', 'distinctSizesSimHei');
        
        // 处理 cursive 字体测量
        processFontMeasurements('Cursive', 'textCanvasCursive', 'resultsCursive', 'distinctSizesCursive');
    </script>
</body>
</html>